/**
 * Created by Administrator on 2018/12/30.
 */
package com.game.fg.service;

import com.google.protobuf.InvalidProtocolBufferException;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.java_websocket.WebSocket;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Random;


class FGGame {
    private static Logger logger = LogManager.getLogger(FGGame.class.getName());
    //房间奖池
    private static double jackpotOfJunior = 0;//初级房奖池
    private static double jackpotOfMiddle = 0;//中级房奖池
    private static double jackpotOfSenior = 0;//高级房奖池
    private static double taxRate = 0;//当前抽税率
    //救济金
    public static double benefitsOfJunior = 0;//初级房间救济金
    public static double benefitsOfMiddle = 0;//中级房间救济金
    public static double benefitsOfSenior = 0;//高级房间救济金

    //玩家日志队列
    private final static String flag = "110";

    class GameLog {
        int uid;
        int round;
        int result;
        int changeMoney;
        int leftMoney;
        double taxRate;
        String des;
        long time;

        GameLog(int uid, int round, int result, int changeMoney, int leftMoney, double taxRate, String des, long time) {
            this.uid = uid;
            this.round = round;
            this.result = result;
            this.changeMoney = changeMoney;
            this.leftMoney = leftMoney;
            this.taxRate = taxRate;
            this.des = des;
            this.time = time;
        }
    }

    private static Queue<GameLog> userLogQueue = new LinkedList<GameLog>();

    //请求进入游戏大厅
    private void enterGame(WebSocket ws, byte[] byteData) {
        try {
            Message.RequestEnterGame data = Message.RequestEnterGame.parseFrom(byteData);
            int uid = data.getUid();//玩家uid
            String token = data.getToken();//token
            //删除已经在线的玩家
            FGUserManager.getInstance().removeUser(uid, "重复登录");
            //添加玩家
            FGUser newUser = new FGUser(uid, ws);
            FGUserManager.getInstance().addUser(newUser);
            logger.debug(String.format("玩家请求进入游戏 uid:%d  token:%s", uid, token));
            //向认证服务器验证token
            AuthServer.getInstance().authUserLogin(uid, token);

        } catch (InvalidProtocolBufferException e) {
            logger.error("解析协议错误", e);
        } catch (Exception e) {
            logger.error("玩家进入游戏错误", e);
        }
    }

    //请求进入游戏房间
    private void startGame(WebSocket ws, byte[] byteData) {
        try {
            Message.RequestStartGame data = Message.RequestStartGame.parseFrom(byteData);
            FGUser user = FGUserManager.getInstance().getUser(ws);
            if (user == null) {   //玩家不存在(需要先EnterGame)
                FGWebSocket.send(ws, FGConst.S2C_StartGame, MessageBuild.responseStartGame(Message.EnumErrorCode.UNLOGIN));
                logger.debug("玩家进入房间失败 未登录");
                return;
            }
            //判断金币是否充足
            int entryFee = FGConfig.getInstance().entryFeeOfJunior;
            if (data.getRoomType() == Message.EnumRoomType.MIDDLE) {
                entryFee = FGConfig.getInstance().entryFeeOfMiddle;
            } else if (data.getRoomType() == Message.EnumRoomType.SENIOR) {
                entryFee = FGConfig.getInstance().entryFeeOfSenior;
            }

            if (user.getMoney() < entryFee) {
                FGWebSocket.send(ws, FGConst.S2C_StartGame, MessageBuild.responseStartGame(Message.EnumErrorCode.OUTOFMONEY));
                logger.debug(String.format("玩家进入房间失败 金币不足 uid:%d  money:%d needMoney:%d", user.getUid(), user.getMoney(), entryFee));
                return;
            }
            //扣除报名费
            //user.updateMoney(-entryFee, FGConst.MoneySrc_GAME_LOSE);
            //更新当天净分: 输赢分
            user.setDayWinLoseScore(user.getDayWinLoseScore() - entryFee);
            //更新总净分
            user.setTotalWinLoseScore(user.getTotalWinLoseScore() - entryFee);
            //标记玩家当前进入的房间类型
            user.setRoomType(data.getRoomType());
            //返回客户端开始游戏成功
            FGWebSocket.send(ws, FGConst.S2C_StartGame, MessageBuild.responseStartGame(Message.EnumErrorCode.SUCCESS));
            logger.debug(String.format("进入房间 uid:%d  money:%d roomType:%d", user.getUid(), user.getMoney(), data.getRoomType().ordinal()));

        } catch (Exception e) {
            logger.error("玩家开始游戏错误", e);
        }
    }

    //开始猜拳
    private void playGame(WebSocket ws, byte[] byteData) {
        try {
            FGUser user = FGUserManager.getInstance().getUser(ws);
            //玩家是否进入游戏
            if (user == null) {
                FGWebSocket.send(ws, FGConst.S2C_PlayGame, MessageBuild.responsePlayGame(Message.EnumErrorCode.UNLOGIN, Message.EnumGameResult.LOSE, 0, 0));
                logger.debug("猜拳失败 未登录");
                return;
            }
            Message.EnumRoomType roomType = user.getRoomType();
            //玩家是否开始游戏
            if (roomType == null) {
                FGWebSocket.send(ws, FGConst.S2C_PlayGame, MessageBuild.responsePlayGame(Message.EnumErrorCode.NOTSTARTGAME, Message.EnumGameResult.LOSE, 0, user.getMoney()));
                logger.debug(String.format("猜拳失败 未开始游戏 uid:%d  money:%d", user.getUid(), user.getMoney()));
                return;
            }
            int entryFee = FGConfig.getInstance().getEntryFee(roomType);
            //金币是否充足
            if (user.getMoney() < entryFee) {
                FGWebSocket.send(ws, FGConst.S2C_PlayGame, MessageBuild.responsePlayGame(Message.EnumErrorCode.OUTOFMONEY, Message.EnumGameResult.LOSE, 0, user.getMoney()));
                logger.debug(String.format("猜拳失败 金币不足 uid:%d  leftMoney:%d needMoney:%d", user.getUid(), user.getMoney(), entryFee));
                return;
            }
            //是否已经赢了3个回合
            int userRound = user.getRound();
            if (userRound > 2) {
                FGWebSocket.send(ws, FGConst.S2C_PlayGame, MessageBuild.responsePlayGame(Message.EnumErrorCode.ROUNDEND, Message.EnumGameResult.LOSE, 0, user.getMoney()));
                logger.debug(String.format("猜拳失败 三回合已经结束先要抽奖 uid:%d  money:%d", user.getUid(), user.getMoney()));
                return;
            }
            //如果是第一回合则扣除报名费
            if (userRound == 0) {
                user.updateMoney(-entryFee, FGConst.MoneySrc_GAME_LOSE);
            }
            //当全游戏抽税几率小于停止波动配置的几率时则触发第一套配置
            //当全游戏抽税几率大于触发波动配置的几率时则触发第二套配置
            boolean normal = true;
            if (getTaxRate() < FGConfig.getInstance().taxRateOfNormal) {
                normal = true;
            } else if (getTaxRate() > FGConfig.getInstance().taxRateOfAbnormal) {
                normal = false;
            }
            //标记玩家正常、非正常配置
            user.setNormal(normal);
            //判断输赢
            Message.EnumGameResult res = Message.EnumGameResult.LOSE;
            //第三把猜拳 当前奖池数值不超过奖池安全线直接判定为输
            if (userRound != 2 || getJackpot(roomType) >= FGConfig.getInstance().getSafeLine(roomType)) {
                //根据当前配置类型/房间类型/回合获取输赢平概率
                FGConfig.Probability p = FGConfig.getInstance().getProbabilityByRound(normal, roomType, userRound);
                int totalRate = p.getTieRate() + p.getWinRate() + p.getLoseRate();
                Random rand = new Random();
                int randRate = rand.nextInt(totalRate);
                if (randRate <= p.getTieRate()) {
                    //平
                    res = Message.EnumGameResult.TIE;
                } else {
                    int winLoseRate = p.getWinRate() + p.getLoseRate();
                    randRate = rand.nextInt(winLoseRate);
                    if (randRate <= p.getWinRate()) {
                        //赢
                        res = Message.EnumGameResult.WIN;
                    }
                }
            }
            //根据今日总净收入判断是否需要重新计算一次胜率 && 今日领取的救济金不大于每日上限
            if (res != Message.EnumGameResult.TIE && user.getDayHelpCoin() < FGConfig.getInstance().getUserMaxGetBenefits()) {
                double totalWinLoseScore = user.getTotalWinLoseScore();
                double buffer = FGConfig.getInstance().getBuffer(normal, roomType, totalWinLoseScore);
                double bufferRate = buffer - 10000;
                if (bufferRate != 0) {
                    if (bufferRate > 0) {
                        //重新判断一次赢得概率
                        if (res == Message.EnumGameResult.LOSE) {
                            Random rand = new Random();
                            int randRate = rand.nextInt(10000);
                            if (randRate < bufferRate) {
                                res = Message.EnumGameResult.WIN;
                                //标记是补助判赢
                                user.setHelpWin(true);
                                logger.debug(String.format("玩家补助判胜 uid:%d round:%d roomType:%d", user.getUid(), user.getRound(), roomType.ordinal()));

                            }
                        }
                    } else if (res == Message.EnumGameResult.WIN) {
                        //重新判断一次输得概率
                        Random rand = new Random();
                        int randRate = rand.nextInt(10000);
                        if (randRate < -bufferRate) {
                            res = Message.EnumGameResult.LOSE;
                            logger.debug(String.format("玩家补助判输 uid:%d round:%d roomType:%d", user.getUid(), user.getRound(), roomType.ordinal()));
                        }
                    }
                }
            }

            //实际获得或者减少的金币数量
            int changeMoney = 0;
            String gameResult = "平";
            if (res == Message.EnumGameResult.WIN) {
                gameResult = "赢";
                if (userRound == 2) {
                    //三局全胜则随机金币
                    changeMoney = FGConfig.getInstance().getLotteryMoney(user.isNormal(), roomType);
                    //更新游戏相关数据
                    updateGameData(normal, user, res, changeMoney);
                    //扣除奖池
                    updateJackpot(roomType, -changeMoney);
                    //更新可领取的金币
                    user.setCanGetMoney(user.getCanGetMoney() + changeMoney);
                    user.clear();
                } else {
                    changeMoney = entryFee * (int) Math.pow(2, (double) userRound + 1);
                    //更新游戏相关数据
                    updateGameData(normal, user, res, changeMoney);
                    //更新回合数
                    user.setRound(userRound + 1);
                    //更新可领取的金币
                    user.setCanGetMoney(user.getCanGetMoney() + changeMoney);
                }
                //如果是补助判赢则更新今日已经领取的救济金数量
                if (user.isHelpWin()) {
                    user.setHelpWin(false);
                    user.setDayHelpCoin(user.getDayHelpCoin() + changeMoney);
                    //更新当前房间补助金
                    double benefits = getBenefits(roomType);
                    if (benefits >= changeMoney) {
                        updateBenefits(roomType, -changeMoney);
                    } else {
                        //如果房间救济金不够则从全局救济金扣除
                        optGlobalCoinPool(1, changeMoney, benefits, roomType.ordinal());
                    }
                }

            } else if (res == Message.EnumGameResult.LOSE) {
                gameResult = "输";
                changeMoney = -entryFee;
                //更新游戏相关数据
                updateGameData(normal, user, res, changeMoney);
                //如果输则清零回合数
                user.setRound(0);
            } else {
                //平局
                addGameLog(user.getUid(), userRound, Message.EnumGameResult.TIE_VALUE, 0, user.getMoney(), 0, String.format("%d回合平", userRound + 1));
            }
            //返回客户端
            FGWebSocket.send(ws, FGConst.S2C_PlayGame, MessageBuild.responsePlayGame(Message.EnumErrorCode.SUCCESS, res, changeMoney, user.getMoney()));
            logger.debug(String.format("玩家猜拳 uid:%s normal:%b round:%d res:%s ", user.getUid(), normal, userRound, gameResult));
        } catch (Exception e) {
            logger.error("玩家猜拳错误", e);
        }
    }

    //离开游戏
    private void exitGame(WebSocket ws, byte[] byteData) {
        try {
            FGUser user = FGUserManager.getInstance().getUser(ws);
            if (user != null) {
                //增加金币
                if (user.getCanGetMoney() != 0) {
                    user.updateMoney(user.getCanGetMoney(), FGConst.MoneySrc_GAME_WIN);
                }
                //更新当天净分: 输赢分
                user.setDayWinLoseScore(user.getDayWinLoseScore() + user.getCanGetMoney());
                //更新总净分
                user.setTotalWinLoseScore(user.getTotalWinLoseScore() + user.getCanGetMoney());
                //清零数据
                user.clear();
                FGWebSocket.send(ws, FGConst.S2C_ExitGame, MessageBuild.responseExitGame(Message.EnumErrorCode.SUCCESS));
                //回写数据到认证服务器
                AuthServer.getInstance().writeUserData(user);
                //设置玩家时间
                long playTime = System.currentTimeMillis() / 1000 - user.getEnterGameTime();
                user.setTotalOnlineTime((int) (user.getTotalOnlineTime() + playTime));
                user.setTotalPlayTime((int) (user.getTotalPlayTime() + playTime));
                user.setDayOnlineTime((int) (user.getDayPlayTime() + playTime));
                user.setDayPlayTime((int) (user.getDayPlayTime() + playTime));
                logger.debug(String.format("见好就收(离开游戏) uid:%d money:%d", user.getUid(), user.getMoney()));
            }
        } catch (Exception e) {
            logger.error("玩家离开游戏错误", e);
        }
    }

    //请求兑换金币
    private void exchangeMoney(WebSocket ws, byte[] byteData) {
        try {
            FGUser user = FGUserManager.getInstance().getUser(ws);
            if (user != null) {
                Message.RequestExchange data = Message.RequestExchange.parseFrom(byteData);
                int type = data.getType();
                int value = data.getValue();
                if (type == 1) {
                    //游戏金币兑换趣头条金币
                    if (user.getMoney() < value) {
                        //金币不足
                        FGWebSocket.send(ws, FGConst.S2C_Exchange, MessageBuild.responseExchange(Message.EnumErrorCode.OUTOFMONEY, type, value, user.getMoney()));
                        logger.debug(String.format("兑换失败 金币不足 uid:%d type:%d value:%d leftMoney:%d", user.getUid(), type, value, user.getMoney()));
                        return;
                    }
                    //判断次数和兑换的数量是否达到上限
                    if (user.getCfgSaleTNum() < user.getDaySaleTNum()) {
                        FGWebSocket.send(ws, FGConst.S2C_Exchange, MessageBuild.responseExchange(Message.EnumErrorCode.EXCHANGEMONEYTIMESLIMIT, type, value, user.getMoney()));
                        logger.debug(String.format("兑换失败 今日兑换次数不足 uid:%d type:%d value:%d leftMoney:%d", user.getUid(), type, value, user.getMoney()));
                        return;
                    }
                    if (user.getCfgSaleCNum() < user.getDaySaleCNum()) {
                        FGWebSocket.send(ws, FGConst.S2C_Exchange, MessageBuild.responseExchange(Message.EnumErrorCode.EXCHANGEMONEYCOUNTLIMIT, type, value, user.getMoney()));
                        logger.debug(String.format("兑换失败 今日兑换数量已达到上限 uid:%d type:%d value:%d leftMoney:%d", user.getUid(), type, value, user.getMoney()));
                        return;
                    }
                } else {
                    //趣头条金币兑换游戏币
                    if (user.getCfgBuyTNum() < user.getDayBuyTNum()) {
                        FGWebSocket.send(ws, FGConst.S2C_Exchange, MessageBuild.responseExchange(Message.EnumErrorCode.EXCHANQTTGETIMESLIMIT, type, value, user.getMoney()));
                        logger.debug(String.format("兑换失败 今日购买游戏金币次数不足 uid:%d type:%d value:%d leftMoney:%d", user.getUid(), type, value, user.getMoney()));
                        return;
                    }
                    if (user.getCfgBuyCNum() < user.getDayBuyCNum()) {
                        FGWebSocket.send(ws, FGConst.S2C_Exchange, MessageBuild.responseExchange(Message.EnumErrorCode.EXCHANGEQTTCOUNTLIMIT, type, value, user.getMoney()));
                        logger.debug(String.format("兑换失败 今日购买游戏金币数量已达到上限 uid:%d type:%d value:%d leftMoney:%d", user.getUid(), type, value, user.getMoney()));
                        return;
                    }
                }
                String res = exchangeCoin(user.getAppID(), user.getUid(), type, value);
                JSONObject obj = new JSONObject(res);
                int code = obj.getInt("returnCode");
                String msg = obj.getString("returnMsg");
                if (code != 200) {
                    logger.debug(String.format("兑换失败 uid:%d code:%d msg:%s type:%d value:%d leftMoney:%d", user.getUid(), code, msg, type, value, user.getMoney()));
                    FGWebSocket.send(ws, FGConst.S2C_Exchange, MessageBuild.responseExchange(Message.EnumErrorCode.FAIL, type, value, user.getMoney()));
                    return;
                }
                if (type == 1) {
                    user.updateMoney(-value, FGConst.MoneySrc_QTT_ADD);
                    //更新次数
                    user.setDaySaleTNum(user.getDaySaleTNum() + 1);
                    user.setDaySaleCNum(user.getDaySaleCNum() + value);
                    AuthServer.getInstance().writeUserData(user);
                } else {
                    user.updateMoney(value, FGConst.MoneySrc_QTT_SUB);
                    //更新次数
                    user.setDayBuyTNum(user.getDayBuyTNum() + 1);
                    user.setDayBuyCNum(user.getDayBuyCNum() + value);
                    AuthServer.getInstance().writeUserData(user);
                }
                FGWebSocket.send(ws, FGConst.S2C_Exchange, MessageBuild.responseExchange(Message.EnumErrorCode.SUCCESS, type, value, user.getMoney()));
                logger.debug(String.format("兑换成功 uid:%d code:%d msg:%s type:%d value:%d leftMoney:%d", user.getUid(), code, msg, type, value, user.getMoney()));
            }
        } catch (Exception e) {
            logger.error("兑换错误", e);
        }
    }

    //更新游戏相关数据-奖池、抽税率
    private void updateGameData(boolean normal, FGUser user, Message.EnumGameResult res, int changeMoney) {
        try {
            //进入奖池的金币
            double preJackpot = 0;
            //本回合抽税率
            double roundTaxRate = 0;
            //进入救济金的金币数量
            double preBenefits = 0;
            //报名费
            int entryFee = FGConfig.getInstance().getEntryFee(user.getRoomType());
            //第一回合
            if (user.getRound() == 0) {
                //(报名费-第一把猜拳胜率*获胜返还金币)*80%
                FGConfig.Probability p = FGConfig.getInstance().getProbabilityByRound(normal, user.getRoomType(), 0);
                double winRate = p.getWinRate() / (double) (p.getWinRate() + p.getLoseRate());
                double baseValue = entryFee - winRate * entryFee * 2;
                preJackpot = baseValue * 0.7;
                preBenefits = baseValue * 0.1;
                roundTaxRate = (entryFee - winRate * entryFee * 2) * 0.2;
                //记录玩家当前回合进入奖池的数量
                user.setJackpotOfRound0(preJackpot);
                //记录第一回合抽税率
                user.setTaxRateOfRound0(roundTaxRate);
                //记录第一回合进入救济金的数量
                user.setBenefitsOfRound0(preBenefits);
            } else if (user.getRound() == 1) {
                //(报名费-第一把猜拳胜率*第二把猜拳胜率*获胜返还金币)*80%-第一把猜拳进入奖池部分
                FGConfig.Probability p0 = FGConfig.getInstance().getProbabilityByRound(normal, user.getRoomType(), 0);
                double winRate0 = p0.getWinRate() / (double) (p0.getWinRate() + p0.getLoseRate());
                FGConfig.Probability p1 = FGConfig.getInstance().getProbabilityByRound(normal, user.getRoomType(), 1);
                double winRate1 = p1.getWinRate() / (double) (p1.getWinRate() + p1.getLoseRate());
                int getMoney = entryFee * 4;
                double baseValue = entryFee - winRate0 * winRate1 * getMoney;
                double jackpotOfRound0 = user.getJackpotOfRound0();
                double benefitsOfRound0 = user.getBenefitsOfRound0();
                double taxRate0 = user.getTaxRateOfRound0();
                preJackpot = baseValue * 0.7 - jackpotOfRound0;
                preBenefits = baseValue * 0.1 - benefitsOfRound0;
                roundTaxRate = (entryFee - winRate0 * winRate1 * entryFee * 4) * 0.2 - taxRate0;
                //记录玩家当前回合进入奖池的数量
                user.setJackpotOfRound1(preJackpot);
                //记录第二回合抽税率
                user.setTaxRateOfRound1(roundTaxRate);
                //记录第二回合进入救济金的数量
                user.setBenefitsOfRound1(preBenefits);
            } else if (user.getRound() == 2) {
                if (res == Message.EnumGameResult.WIN) {
                    FGConfig.Probability p0 = FGConfig.getInstance().getProbabilityByRound(normal, user.getRoomType(), 0);
                    double winRate0 = p0.getWinRate() / (double) (p0.getWinRate() + p0.getLoseRate());
                    FGConfig.Probability p1 = FGConfig.getInstance().getProbabilityByRound(normal, user.getRoomType(), 1);
                    double winRate1 = p1.getWinRate() / (double) (p1.getWinRate() + p1.getLoseRate());
                    FGConfig.Probability p2 = FGConfig.getInstance().getProbabilityByRound(normal, user.getRoomType(), 2);
                    double winRate2 = p2.getWinRate() / (double) (p2.getWinRate() + p2.getLoseRate());
                    double taxRate0 = user.getTaxRateOfRound0();
                    double taxRate1 = user.getTaxRateOfRound1();
                    //计算第三回合抽税率
                    roundTaxRate = (entryFee - entryFee * 8 * winRate0 * winRate1 * winRate2) * 0.2 - taxRate0 - taxRate1;
                    //报名费*2*2*2-第一次猜拳进入奖池部分-第二次猜拳进入奖池部分
                    double jackpotOfRound0 = user.getJackpotOfRound0();
                    double jackpotOfRound1 = user.getJackpotOfRound1();
                    preJackpot = entryFee * 8 - jackpotOfRound0 - jackpotOfRound1 - (taxRate0 + taxRate1 + roundTaxRate) / 10000.0 * entryFee;
                    //三局都赢则重置抽税率
                    double taxRate = (1 - (taxRate0 + (taxRate1 + taxRate0) / 2.0 + (taxRate0 + taxRate1 + roundTaxRate) / 3.0) / (3.0 * entryFee)) * 10000;
                    setTaxRate(taxRate);
                    //计算进入救济金奖池的数量
                    double benefitsOfRound0 = user.getBenefitsOfRound0();
                    double benefitsOfRound1 = user.getBenefitsOfRound1();
                    preBenefits = (entryFee - winRate0 * winRate1 * winRate2 * entryFee * 8) * 0.1 - benefitsOfRound0 - benefitsOfRound1;

                } else if (res == Message.EnumGameResult.LOSE) {
                    //(报名费-第一把猜拳胜率*第二把猜拳胜率*第三把猜拳胜率*获胜返还金币)*80%-第一把猜拳进入奖池部分-第二把猜拳奖池部分
                    FGConfig.Probability p0 = FGConfig.getInstance().getProbabilityByRound(normal, user.getRoomType(), 0);
                    double winRate0 = p0.getWinRate() / (double) (p0.getWinRate() + p0.getLoseRate());
                    FGConfig.Probability p1 = FGConfig.getInstance().getProbabilityByRound(normal, user.getRoomType(), 1);
                    double winRate1 = p1.getWinRate() / (double) (p1.getWinRate() + p1.getLoseRate());
                    FGConfig.Probability p2 = FGConfig.getInstance().getProbabilityByRound(normal, user.getRoomType(), 2);
                    double winRate2 = p2.getWinRate() / (double) (p2.getWinRate() + p2.getLoseRate());
                    int getMoney = entryFee * 8;
                    double jackpotOfRound0 = user.getJackpotOfRound0();
                    double jackpotOfRound1 = user.getJackpotOfRound1();
                    preJackpot = (entryFee - winRate0 * winRate1 * winRate2 * getMoney) * 0.7 - jackpotOfRound0 - jackpotOfRound1;
                }
            }
            Message.EnumRoomType roomType = user.getRoomType();
            //更新房间奖池
            updateJackpot(roomType, preJackpot);
            //更新房间救济金
            updateBenefits(roomType, preBenefits);
            //游戏日志
            String logDes = String.format("%d回合赢", user.getRound() + 1);
            if (res == Message.EnumGameResult.LOSE) {
                logDes = String.format("%d回合输", user.getRound() + 1);
            }
            addGameLog(user.getUid(), user.getRound(), res.ordinal(), changeMoney, user.getMoney(), roundTaxRate, logDes);
        } catch (Exception e) {
            logger.error("更新奖池错误", e);
        }
    }

    //更新房间奖池数量
    private void updateJackpot(Message.EnumRoomType roomType, double value) {
        //放入线程池执行
        //Jedis redis = FGRedis.getInstance().getJedis();
        if (roomType == Message.EnumRoomType.JUNIOR) {
            //String key = String.format("CQ:%d:jackpotOfJunior", ManagerServer.serverInfo.serverID);
            jackpotOfJunior += value;
            //redis.set(key, String.valueOf(jackpotOfJunior));
        } else if (roomType == Message.EnumRoomType.MIDDLE) {
            //String key = String.format("CQ:%d:jackpotOfMiddle", ManagerServer.serverInfo.serverID);
            jackpotOfMiddle += value;
            //redis.set(key, String.valueOf(jackpotOfMiddle));
        } else if (roomType == Message.EnumRoomType.SENIOR) {
            // String key = String.format("CQ:%d:jackpotOfSenior", ManagerServer.serverInfo.serverID);
            jackpotOfSenior += value;
            // redis.set(key, String.valueOf(jackpotOfSenior));
        }
        //logger.debug(String.format("更新奖池 roomType:%d value:%.2f", roomType.ordinal(), value));
    }

    //获取房间奖池数量
    private double getJackpot(Message.EnumRoomType roomType) {
        if (roomType == Message.EnumRoomType.SENIOR) {
            return jackpotOfSenior;
        } else if (roomType == Message.EnumRoomType.MIDDLE) {
            return jackpotOfMiddle;
        }
        return jackpotOfJunior;
    }

    //更新房间救济金
    private void updateBenefits(Message.EnumRoomType roomType, double value) {
        //Jedis redis = FGRedis.getInstance().getJedis();
        if (roomType == Message.EnumRoomType.JUNIOR) {
            //String key = String.format("CQ:%d:benefitsOfJunior", ManagerServer.serverInfo.serverID);
            benefitsOfJunior += value;
            // redis.set(key, String.valueOf(benefitsOfJunior));
        } else if (roomType == Message.EnumRoomType.MIDDLE) {
            // String key = String.format("CQ:%d:benefitsOfMiddle", ManagerServer.serverInfo.serverID);
            benefitsOfMiddle += value;
            // redis.set(key, String.valueOf(benefitsOfMiddle));
        } else if (roomType == Message.EnumRoomType.SENIOR) {
            String key = String.format("CQ:%d:benefitsOfSenior", ManagerServer.serverInfo.serverID);
            benefitsOfSenior += value;
            //redis.set(key, String.valueOf(benefitsOfSenior));
        }
        //logger.debug(String.format("更新救济金 roomType:%d value:%.2f", roomType.ordinal(), value));
    }

    //根据房间类型获取救济金
    private double getBenefits(Message.EnumRoomType roomType) {
        if (roomType == Message.EnumRoomType.JUNIOR) {
            return benefitsOfJunior;
        } else if (roomType == Message.EnumRoomType.MIDDLE) {
            return benefitsOfMiddle;
        }
        return benefitsOfSenior;
    }

    private static double getTaxRate() {
        return taxRate;
    }

    private static void setTaxRate(double taxRate) {
        FGGame.taxRate = taxRate;
    }

    //数据库加载游戏数据
    static void loadGameData() {
        /*
        Jedis redis = FGRedis.getInstance().getJedis();
        String jackpotOfJuniorKey = String.format("CQ:%d:jackpotOfJunior", ManagerServer.serverInfo.serverID);
        String jackpotOfMiddleKey = String.format("CQ:%d:jackpotOfMiddle", ManagerServer.serverInfo.serverID);
        String jackpotOfSeniorKey = String.format("CQ:%d:jackpotOfSenior", ManagerServer.serverInfo.serverID);
        String benefitsOfJuniorKey = String.format("CQ:%d:benefitsOfJunior", ManagerServer.serverInfo.serverID);
        String benefitsOfMiddleKey = String.format("CQ:%d:benefitsOfMiddle", ManagerServer.serverInfo.serverID);
        String benefitsOfSeniorKey = String.format("CQ:%d:benefitsOfSenior", ManagerServer.serverInfo.serverID);
        String zeroTimeKey = String.format("CQ:%d:curZeroTime", ManagerServer.serverInfo.serverID);

        String sJackpotOfJunior = redis.get(jackpotOfJuniorKey);
        if (sJackpotOfJunior != null) {
            jackpotOfJunior = Integer.parseInt(sJackpotOfJunior);
        }
        String sJackpotOfMiddle = redis.get(jackpotOfMiddleKey);
        if (sJackpotOfMiddle != null) {
            jackpotOfMiddle = Integer.parseInt(sJackpotOfMiddle);
        }
        String sJackpotOfSenior = redis.get(jackpotOfSeniorKey);
        if (sJackpotOfSenior != null) {
            jackpotOfSenior = Integer.parseInt(sJackpotOfSenior);
        }

        String sBenefitsOfJunior = redis.get(benefitsOfJuniorKey);
        if (sBenefitsOfJunior != null) {
            benefitsOfJunior = Integer.parseInt(sBenefitsOfJunior);
        }
        String sBenefitsOfMiddle = redis.get(benefitsOfMiddleKey);
        if (sBenefitsOfMiddle != null) {
            benefitsOfMiddle = Integer.parseInt(sBenefitsOfMiddle);
        }
        String sBenefitsOfSenior = redis.get(benefitsOfSeniorKey);
        if (sBenefitsOfSenior != null) {
            benefitsOfSenior = Integer.parseInt(sBenefitsOfSenior);
        }
        String sZeroTime = redis.get(zeroTimeKey);
        if (sZeroTime != null) {
            FGTimer.getInstance().setCurZeroTime(Integer.parseInt(sZeroTime), false);
        }
        */
    }


    //数据埋点记录
    private void addGameLog(int uid, int round, int result, int changeMoney, int leftMoney, double taxRate, String des) {
        long time = System.currentTimeMillis() / 1000;
        //判断标志防止多线程访问竞争问题
        /*
        synchronized (flag) {
            userLogQueue.offer(new GameLog(uid, round, result, changeMoney, leftMoney, taxRate, des, time));
        }
        */
    }

    //取玩家日志
    static List<GameLog> getUserLog() {
        int max = 1000;
        int size = userLogQueue.size();
        max = max > size ? size : max;
        List<GameLog> res = new ArrayList<GameLog>();
        //判断标志防止多线程访问竞争问题
        synchronized (flag) {
            for (int i = 0; i < max; i++) {
                if (!userLogQueue.isEmpty()) {
                    res.add(userLogQueue.poll());
                }
            }
        }
        return res;
    }

    //操作全球救济金
    //optType 操作类型（1：从池子中索取 2：向池子中填充）
    //optValue 向全局共济金池子中操作货币数(索取或填充)
    //currentPoolCoin 当前房间池子积分
    static String optGlobalCoinPool(int optType, double optValue, double currentPoolCoin, int roomId) {
        logger.debug(String.format("同步救济金到web optType:%s optValue:%f currentPoolCoin:%f roomId:%d", optType, optValue, currentPoolCoin, roomId));
        HashMap<String, String> paramMap = new HashMap<String, String>();
        paramMap.put("gameId", String.valueOf(ManagerServer.serverInfo.gameID));
        paramMap.put("roomId", String.valueOf(ManagerServer.serverInfo.serverID));
        paramMap.put("optCoin", String.valueOf(optValue));
        paramMap.put("currentPoolCoin", String.valueOf(currentPoolCoin));
        paramMap.put("optType", String.valueOf(optType));
        String url = getUrl(FGConfig.getInstance().serverConfig.getGlobalCoinUrl(), paramMap);
        try {
            return FGHttp.doGet(url);
        } catch (Exception e) {
            logger.error("HTTP请求错误", e);
        }
        return "";
    }

    //货币兑换
    //appId 合作方产品Id
    //uid 平台用户Id
    //optType 操作类型（1：减 2：增）
    //optValue 兑换数量（增或扣，都传正整数）
    private static String exchangeCoin(String appId, int uid, int optType, int optValue) {
        logger.debug(String.format("货币兑换 uid:%s optType:%d optValue:%d appId:%s", uid, optType, optValue, appId));
        HashMap<String, String> paramMap = new HashMap<String, String>();
        paramMap.put("appId", String.valueOf(appId));
        paramMap.put("userId", String.valueOf(uid));
        paramMap.put("cNum", String.valueOf(optValue));
        paramMap.put("optType", String.valueOf(optType));
        paramMap.put("gameId", String.valueOf(ManagerServer.serverInfo.gameID));
        paramMap.put("roomId", String.valueOf(ManagerServer.serverInfo.serverID));
        paramMap.put("type", String.valueOf("game-douzicaiquan"));
        paramMap.put("extend", String.valueOf(0));
        String url = getUrl(FGConfig.getInstance().serverConfig.getExchangeUrl(), paramMap);
        try {
            logger.debug(String.format("兑换货币 url:%s", url));
            return FGHttp.doGet(url);
        } catch (Exception e) {
            logger.error("HTTP请求错误", e);
        }
        return "";
    }

    private static String getUrl(String url, HashMap<String, String> params) {
        // 添加url参数
        if (params != null) {
            Iterator<String> it = params.keySet().iterator();
            StringBuffer sb = null;
            while (it.hasNext()) {
                String key = it.next();
                String value = params.get(key);
                if (sb == null) {
                    sb = new StringBuffer();
                    sb.append("?");
                } else {
                    sb.append("&");
                }
                sb.append(key);
                sb.append("=");
                sb.append(value);
            }
            url += sb.toString();
        }
        return url;
    }


    //客户端协议处理
    void msgParse(WebSocket ws, int cmd, byte[] byteData) {
        switch (cmd) {
            case FGConst.C2S_EnterGame: {
                enterGame(ws, byteData);
            }
            break;
            case FGConst.C2S_StartGame: {
                startGame(ws, byteData);
            }
            break;
            case FGConst.C2S_PlayGame: {
                playGame(ws, byteData);
            }
            break;
            case FGConst.C2S_ExitGame: {
                exitGame(ws, byteData);
            }
            break;
            case FGConst.C2S_Exchange: {
                exchangeMoney(ws, byteData);
            }
            break;
            default: {
                logger.warn(String.format("未知的协议 ip:%s cmd:%d", ws.getRemoteSocketAddress(), cmd));
            }
            break;

        }
    }
}
